package com.xpec.c4.game.system;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.cmdlinetool.BuildDatabaseTables;
import com.start.XStart;
import com.xpec.c4.db.basic.BasicGameDAO;
import com.xpec.c4.db.basic.BasicLogDAO;
import com.xpec.c4.db.hibernate.manager.HibernateAnalysisManager;
import com.xpec.c4.db.hibernate.manager.HibernateBusinessManager;
import com.xpec.c4.db.hibernate.manager.HibernateLogManager;
import com.xpec.c4.db.hibernate.manager.HibernateManager;
import com.xpec.c4.service.module.ModuleServer;
import com.xpec.c4.service.module.PropertyKey;
import com.xpec.c4.service.module.ServerProperties;

/**
 * 游戏服务端的启动程序
 * 
 * @author Bany
 * 
 * @since 2008-8-30 下午05:37:05
 * 
 */

public class ServerMain {

	/**
	 * 版本...不知道耶這個版號是不是只能手動增加...
	 */
	public static short MT_VERSION_MAJOR = 0;
	
	/**
	 * 版本
	 */
	public static short MT_VERSION_MINOR = 7;
	
	/**
	 * 版本
	 */
	public static short MT_VERSION_BUILD = 0;
	
	/**
	 * 服务器名称
	 */
	@SuppressWarnings("unused")
	private static final String SERVER_NAME = "-ServerName=";

	/**
	 * 服务器配置
	 */
	@SuppressWarnings("unused")
	private static final String SERVER_INFO_CONFIG = "-ServerInfoConfig=";

	private static final Log log = LogFactory.getLog(ServerMain.class);

	/**
	 * 啟動moduleServer一定要先加載或設定ServerName
	 */
	private static ModuleServer server;
	
	/**
	 * 每此重新開啟server時的執行號碼,log debug用
	 */
	public final static long serverRunBatchNo = System.currentTimeMillis();

	
	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		
		// BuildDatabaseTables.main(args);
		
		// 授權驗證<br>
		// 啟動過程不寫在這裡, 即便是拿掉底下的exit一樣不能啟動
		// 這段先測試, 未來啟動過程應該放在 xStart 和 AuthorizeEntry內
		XStart start = new XStart();
		
		if(!start.init()){
			System.exit(0);
		}
		
		StartInfo startInfo = new StartInfo();
		
		if(!start.startup(args, startInfo)){
			System.exit(0);
		}
	}

	/**
	 * 
	 * 
	 * @throws Exception
	 */
	public void init(ServerMain main) throws Exception {
		Runtime.getRuntime().addShutdownHook(new ShutdownHook(main));
		Thread.setDefaultUncaughtExceptionHandler(new ThreadExceptionHandler());
		
		//DB
		// 根據設定值決定要不要自動建立 db 資料表
		if (ServerProperties.getBoolean(PropertyKey.auto_create_db_table, true)) {
			BuildDatabaseTables.build();
		}
		HibernateManager.getSession();
		HibernateLogManager.getSession();
		HibernateBusinessManager.getSession();
		HibernateAnalysisManager.getSession();
//		JedisManager.initial();
	}

	/**
	 * 
	 * 
	 * @param args
	 * @throws Exception
	 */
	public void init(String[] args) throws Exception {
	}

	/**
	 * 服务启动
	 * 
	 * @throws Exception
	 */
	public void start() throws Exception {
		log.info("========== server starting ========== serverRunBatchNo = " + serverRunBatchNo);
		server.start(true);
		server.createSignalFile(true);
		log.info("========== server start success ==========");
	}

	/**
	 * 服务停止
	 * 
	 * @throws Exception
	 */
	public void stop() throws Exception {

		stopServer();
	}

	public void stopServer() {
		log.info("==========server stoping==========");

		server.stop();
	}

	/**
	 * 服务结束
	 * 
	 * @throws Exception
	 */
	public void destroy() throws Exception {
	}
	
	
	public static void modifyGameDBColumn(){
		List<String> listGame = new ArrayList<String>();

//		// 刪掉不用的字段
//		listGame.add("alter table players_2 drop column combatpower");
//		
//		//刪掉移到thirdModel的
//		listGame.add("alter table players_2 drop column constellationShard");
//		listGame.add("alter table players_2 drop column starDust");
//		listGame.add("alter table players_2 drop column starSoulExp");
//		listGame.add("alter table players_2 drop column constellationComponent");
//		listGame.add("alter table players_2 drop column bagStarSoulList");
//		listGame.add("alter table players_2 drop column huntGroundStarSoulList");
//		listGame.add("alter table players_2 drop column starSoulEquipmentSlots");
//		listGame.add("alter table players_2 drop column starFairyComponent");
//		
//		listGame.add("alter table inactive_players_2 drop column constellationShard");
//		listGame.add("alter table inactive_players_2 drop column starDust");
//		listGame.add("alter table inactive_players_2 drop column starSoulExp");
//		listGame.add("alter table inactive_players_2 drop column constellationComponent");
//		listGame.add("alter table inactive_players_2 drop column bagStarSoulList");
//		listGame.add("alter table inactive_players_2 drop column huntGroundStarSoulList");
//		listGame.add("alter table inactive_players_2 drop column starSoulEquipmentSlots");
//		listGame.add("alter table inactive_players_2 drop column starFairyComponent");
//		
//		// 信件標題大小
//		listGame.add("alter table mails modify column title VARCHAR(100) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		listGame.add("alter table inactive_mails modify column title VARCHAR(100) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		
//		
//        //game数据结构异动，更改表结构
//		listGame.add("alter table players add column teleportLasttime bigint(20) default 0 null");
//		//设置mysql对大小写敏感
//		listGame.add("alter table players modify column name VARCHAR(255) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		listGame.add("alter table players modify column accountId VARCHAR(255) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		listGame.add("alter table inactive_players modify column accountId VARCHAR(255) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		listGame.add("alter table accounts modify column accountId VARCHAR(255) BINARY CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL");
//		
//		//给加全服加经验值的表的activityId列添加上唯一性约束
////		listGame.add("ALTER TABLE add_exp_activity ADD unique(activityId)");
//		listGame.add("ALTER TABLE players MODIFY COLUMN attributes VARCHAR(2000) NULL DEFAULT NULL");
//		listGame.add("ALTER TABLE inactive_players MODIFY COLUMN attributes VARCHAR(2000) NULL DEFAULT NULL");
//
//		//炫裝表依玩家guid建立index (因為改寫法了，變成單向one-to-many, hibernate不會把foreign key建立index)
//		listGame.add("ALTER TABLE fancyequips ADD INDEX player_guid (player_guid)");
		

		
		for (String command : listGame) {
			HibernateManager.txBegin();
			try {
				BasicGameDAO.execute(command);
				HibernateManager.txCommitFailRollbackClearSession();
			} catch (Exception e) {
//				log.error(e);
				HibernateManager.txRollback();
			}
		}
		
		//remarked by miriam on 2013/12/3, 目前沒有用(之前是mobile用)
		//execute sql patch from file:其中任何一句sql失敗就該中斷sql執行(不該發生的嚴重錯誤)
//		String sqls[] = getSqlPatch();
//		HibernateManager.txBegin();
//		try {
//			for(String sql : sqls) {
//				BasicGameDAO.execute(sql);
//			}
//			HibernateManager.txCommitFailRollbackClearSession();
//		} catch (Exception e) {
//			log.error("SQL Error -", e);
//			HibernateManager.txRollback();
//		}
		
		HibernateManager.clearSession();
		
		
	}
	
//	/**
//	 * 
//	 */
//	public static void modifyGlobalDBColumn(){
//		
//		List<String> listGlobal = new ArrayList<String>();
//		
////		// 這種加索引的方式會越加越多
////		listGlobal.add("ALTER TABLE batches ADD unique(batchId)");
//
//		for (String command : listGlobal) {
//			HibernateGlobalManager.txBegin();
//			try {
//				BasicGlobalDAO.execute(command);
//				HibernateGlobalManager.txCommitFailRollbackClearSession();
//			} catch (Exception e) {
////				log.error(e);
//				HibernateGlobalManager.txRollback();
//			}
//		}
//		HibernateGlobalManager.clearSession();
//	}
	
	
	public static void modifyLogDBColumn(){
		List<String> listLog=new ArrayList<String>();
		
//		//log数据结构异动，更改表结构
//		listLog.add("alter table camp_change modify column pay BIT(1) null");

		
		for (String command : listLog) {
			HibernateLogManager.txBegin();
			try {
				BasicLogDAO.execute(command);
				HibernateLogManager.txCommitFailRollbackClearSession();
			} catch (Exception e) {
//				log.error(e);
				HibernateLogManager.txRollback();
			}
		}
		HibernateLogManager.clearSession();
		
	}
	
	/**
	 * 
	 */
	private static void removeLogField(){
		
		//log数据结构异动，更改表结构
		List<String> listLog = new ArrayList<String>();
		for (String command : listLog) {
			HibernateLogManager.txBegin();
			try {
				BasicLogDAO.execute(command);
				HibernateLogManager.txCommitFailRollbackClearSession();
			} catch (Exception e) {
				HibernateLogManager.txRollback();
			}
		}
		HibernateLogManager.clearSession();
	}
	
	
	/**
	 * 
	 */
	public static void modifyColumn(){
		// 不知道為什麼alter 不見得會成功
		modifyGameDBColumn();
		modifyLogDBColumn();
//		if( ServerProperties.getBoolean("db_global_enable", false)){
//			modifyGlobalDBColumn();
//		}
		
		
		// 一段時間後就註掉吧
		removeLogField();
	}
	
	//remarked by miriam on 2013/12/3, 目前沒有用(之前是mobile用)
	//新增player_global table:為player編unique id,以此id計算player的icon path
//	public static String[] getSqlPatch() {
//		String[] sqls = {};
//		String sqlFile = "sql" + File.separator + "player_global.sql";
//		InputStream is = Utility.getFileInputStream(sqlFile);
//		
//		if(is == null) return sqls;
//		try {
//			String content = Utility.readFully(is, "UTF-8");
//			Integer maxPlayerCntPerServer = 1000000000;
//			DecimalFormat format = new DecimalFormat();
//			format.setGroupingUsed(false);
//			String pkStartFrom = format.format((long)(Math.random() * 9000000001L) * maxPlayerCntPerServer);
//			String sqlStr = content.replace("{startNum}", pkStartFrom);
//			sqls = sqlStr.split("--##");
//		} catch (IOException e) {
//			log.error(e);
//		} finally {
//			try	{
//				if(null != is)	is.close();
//			} catch (IOException e) {
//				log.error(e);
//			}
//		}
//		return sqls;
//	}		

	public static void setServer(ModuleServer server) {
		ServerMain.server = server;
	}

	/**
	 * 建立.on文件，以便启动脚本知道启动成功了
	 */
}

/**
 * 关服线程
 * 
 * @author lipeilin
 * @2010-8-30下午07:15:56
 * 
 */
class ShutdownHook extends Thread {

	@SuppressWarnings("unused")
	private ServerMain server;

	/**
	 * 
	 */
	public ShutdownHook(ServerMain main) {
		server = main;
	}

	@Override
	public void run() {
		//rowan:commnt out
		//server.stopServer();
	}

}

class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler {

	private static final Log log = LogFactory
			.getLog(ThreadExceptionHandler.class);

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		log.error("Uncaught Exception:" + t, e);

	}

}
